﻿using Microsoft.AspNetCore.Mvc.ModelBinding;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;

namespace FakeXiecheng.API.Helper
{
    public class ArrayModelBinder : IModelBinder
    {
        public Task BindModelAsync(ModelBindingContext bindingContext)
        {
            // 检查模型类型是否为可枚举类型（数组、List等）
            // 因为此绑定器专门用于处理数组类型的参数
            if (!bindingContext.ModelMetadata.IsEnumerableType)
            {
                // 如果不是可枚举类型，标记绑定失败，让其他绑定器处理
                bindingContext.Result = ModelBindingResult.Failed();
                return Task.CompletedTask;
            }

            // 通过值提供器获取前端传递的参数值
            // 例如：对于参数名"ids"，获取查询字符串或路由中的"ids"值
            var value = bindingContext.ValueProvider
                .GetValue(bindingContext.ModelName).ToString();

            // 如果获取到的值为空或空白字符串，直接返回null
            // 这样可以处理没有提供参数的情况
            if (string.IsNullOrWhiteSpace(value))
            {
                // 绑定成功但结果为null
                bindingContext.Result = ModelBindingResult.Success(null);
                return Task.CompletedTask;
            }

            // 此时确认：值不为空，且模型类型是可枚举类型
            // 获取可枚举类型中元素的实际类型（比如 List<Guid> 中的 Guid 类型）
            // GenericTypeArguments[0] 获取第一个泛型参数的类型
            var elementType = bindingContext.ModelType.GetTypeInfo().GenericTypeArguments[0];

            // 获取该元素类型的类型转换器
            // 用于将字符串转换为具体的类型（如将字符串"123"转换为Guid）
            var converter = TypeDescriptor.GetConverter(elementType);

            // 将逗号分隔的字符串分割并转换为目标类型的数组
            // 例如："123,456,789" -> [Guid1, Guid2, Guid3]
            var values = value.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries)
                .Select(x => converter.ConvertFromString(x.Trim()))  // 去除空格并类型转换
                .ToArray();

            // 创建目标类型的数组实例
            // 使用Array.CreateInstance动态创建指定类型和长度的数组
            var typedValues = Array.CreateInstance(elementType, values.Length);

            // 将转换后的值复制到新创建的数组中
            values.CopyTo(typedValues, 0);

            // 设置绑定上下文中的模型值为我们创建的数组
            bindingContext.Model = typedValues;

            // 标记绑定成功，并传递绑定后的模型值
            bindingContext.Result = ModelBindingResult.Success(bindingContext.Model);
            return Task.CompletedTask;
        }
    }
}